<template>
	<view>
		<!-- 控制按钮 -->
		<view style="display: flex;padding-top:10px">
			<view style="width:10px"></view>
			<view style="flex:1">
				<button type="warn" @click="recReq" style="font-size:16px;padding:0">请求录音权限</button>
			</view>
			<view style="width:10px"></view>
			<view style="flex:1">
				<button type="primary" @click="recStart" style="font-size:16px;padding:0">开始录音</button>
			</view>
			<view style="width:10px"></view>
			<view style="flex:1">
				<button @click="recStop" style="font-size:16px;padding:0">停止录音</button>
			</view>
			<view style="width:10px"></view>
		</view>

		<!-- 可视化绘制 -->
		<view style="padding:5px 0 0 10px">
			<view style="height:40px;width:300px;background:#999;position:relative;">
				<view style="height:40px;background:#0B1;position:absolute;" :style="{width:recpowerx+'%'}"></view>
				<view style="padding-left:50px; line-height:40px; position: relative;">{{recpowert}}</view>
			</view>

			<!-- 不同的波形样式，只需创建需要用到的canvas就行，canvas需要指定宽高（下面style里指定了300*100） -->
			<view style="padding-top:5px"></view>
			<view>
				<view class="recwave">
					<canvas type="2d" class="recwave-WaveView"></canvas>
				</view>
			</view>
		</view>

		<!-- 日志输出 -->
		<view style="padding-top:10px">
			<view v-if="reclogLast"
				style="position:fixed;z-index:2;width:20vw;min-width:200px;max-height:100px;overflow:auto;right:0;bottom:0;background:#fff;padding:5px 10px;border-radius:6px 0 0 0;box-shadow:-1px -1px 3px #ddd;font-size:13px">
				<view :style="{color:reclogLast.color==1?'red':reclogLast.color==2?'green':reclogLast.color}">
					{{reclogLast.txt}}
				</view>
			</view>
		</view>
		<view style="padding-top:80px"></view>

	</view>
</template>


<script>
	/** 先引入Recorder （ 需先 npm install recorder-core ）**/
	import Recorder from 'recorder-core'; //注意如果未引用Recorder变量，可能编译时会被优化删除（如vue3 tree-shaking），请改成 import 'recorder-core'，或随便调用一下 Recorder.a=1 保证强引用

	/** 引入RecordApp **/
	import RecordApp from 'recorder-core/src/app-support/app.js'
	//【所有平台必须引入】uni-app支持文件
	import '../../uni_modules/Recorder-UniCore/app-uni-support.js'


	/** 可选：App中引入原生录音插件来进行录音，兼容性和体验更好，原生插件市场地址: https://ext.dcloud.net.cn/plugin?name=Recorder-NativePlugin （试用无任何限制）
		在调用RecordApp.RequestPermission之前进行配置，建议放到import后面直接配置（全局生效）
		也可以判断一下只在iOS上或Android上启用，不判断就都启用，比如判断iOS：RecordApp.UniIsApp()==2 */
	RecordApp.UniNativeUtsPlugin = {
		nativePlugin: true
	}; //目前仅支持原生插件，uts插件不可用


	export default {
		data() {
			return {
				recpowerx: 0,
				recpowert: "",
				reclogs: [],
				reclogLast: ""
			}
		},
		mounted() {
			this.isMounted = true;
			this.uniPage__onShow(); //onShow可能比mounted先执行，页面准备好了时再执行一次
		},
		/*#ifdef VUE3*/
		unmounted() /*#endif*/ /*#ifndef VUE3*/ destroyed() /*#endif*/ {
			RecordApp.Stop(); //清理资源，如果打开了录音没有关闭，这里将会进行关闭
		},
		onShow() { //当组件用时没这个回调
			if (this.isMounted) this.uniPage__onShow(); //onShow可能比mounted先执行，页面可能还未准备好
		},
		methods: {
			uniPage__onShow() { //页面onShow时【必须调用】的函数，传入当前组件this
				RecordApp.UniPageOnShow(this);
			},

			// 请求权限
			recReq() {
				this.reclog("正在请求录音权限...");
				RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
				RecordApp.RequestPermission(() => {
					this.reclog("已获得录音权限，可以开始录音了", 2);
				}, (msg, isUserNotAllow) => {
					if (isUserNotAllow) { //用户拒绝了录音权限
						//这里你应当编写代码进行引导用户给录音权限，不同平台分别进行编写
					}
					this.reclog(
						(isUserNotAllow ? "isUserNotAllow," : "") + "请求录音权限失败：" + msg, 1);
				});
			},

			// 开始录音
			recStart() {
				var file = Date.now() + ".mp3";
				this.filePath = "";

				this.reclog("正在打开... 保存到：" + file);
				RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
				RecordApp.Start({
					type: "mp3",
					sampleRate: 16000,
					bitRate: 16,
					onProcess: (buffers, powerLevel, duration, sampleRate, newBufferIdx, asyncEnd) => {
						this.recpowerx = powerLevel;
						this.recpowert = duration + " / " + powerLevel;
					},
					onProcess_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
					//App中是在renderjs中进行的可视化图形绘制
					if(this.waveView){
						this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
					}
				}`

						,
					takeoffEncodeChunk: (chunkBytes) => {
						//这里保存文件到本地
						var base64 = RecordApp.UniBtoa(chunkBytes.buffer);
						RecordApp.UniNativeUtsPluginCallAsync("writeFile", {
							append: true,
							path: file,
							dataBase64: base64
						}).then((data) => {
							this.filePath = data.fullPath;
						}).catch((e) => {
							this.reclog("保存文件失败：" + e.message, 1);
						});
					},
					start_renderjs: `function(){
					//App中可以放一个函数，在Start成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
					//放一些仅在renderjs中才生效的事情，比如初始化，不提供也行
				}`,
					stop_renderjs: `function(aBuf,duration,mime){
					//App中可以放一个函数，在Stop成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
					this.audioData=aBuf; //留着给Stop时进行转码成wav播放
				}`
				}, () => {
					this.reclog("录制中", 2);

					//创建音频可视化图形绘制，App环境下是在renderjs中绘制，H5、小程序等是在逻辑层中绘制，因此需要提供两段相同的代码（宽高值需要和canvas style的宽高一致）
					RecordApp.UniFindCanvas(this, [".recwave-WaveView"], `
						this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
					`, (canvas1) => {
						this.waveView = Recorder.WaveView({
							compatibleCanvas: canvas1,
							width: 300,
							height: 100
						});
					});
				}, (msg) => {
					this.reclog("开始录音失败：" + msg, 1);
				});
			},

			// 停止录音
			recStop() {
				this.reclog("正在结束录音...");
				RecordApp.Stop((aBuf, duration, mime) => {
					this.reclog("启用takeoffEncodeChunk后Stop返回的blob长度为0不提供音频数据");
					this.reclog("文件保存在：" + this.filePath);
					this.playAudio(this.filePath);
				}, (msg) => {
					this.reclog("结束录音失败：" + msg, 1);
				});
			},

			reclog(msg, color) {
				var now = new Date();
				var t = ("0" + now.getHours()).substr(-2) +
					":" + ("0" + now.getMinutes()).substr(-2) +
					":" + ("0" + now.getSeconds()).substr(-2);
				var txt = "[" + t + "]" + msg;
				console.log(txt);
				this.reclogs.splice(0, 0, {
					txt: txt,
					color: color
				});
				this.reclogLast = {
					txt: txt,
					color: color
				};
			},

			playAudio(ret) {
				const innerAudioContext = uni.createInnerAudioContext();
				innerAudioContext.src = ret;
				innerAudioContext.play();
			},


		}
	}
</script>




<!-- #ifdef APP -->
<script module="testMainVue" lang="renderjs">
	/**============= App中在renderjs中引入RecordApp，这样App中也能使用H5录音、音频可视化 =============**/
	/** 先引入Recorder **/
	import Recorder from 'recorder-core'; //注意如果未引用Recorder变量，可能编译时会被优化删除（如vue3 tree-shaking），请改成 import 'recorder-core'，或随便调用一下 Recorder.a=1 保证强引用

	//按需引入需要的录音格式编码器，用不到的不需要引入，减少程序体积；H5、renderjs中可以把编码器放到static文件夹里面用动态创建script来引入，免得这些文件太大
	import 'recorder-core/src/engine/mp3.js'
	import 'recorder-core/src/engine/mp3-engine.js'
	import 'recorder-core/src/engine/wav.js'
	import 'recorder-core/src/engine/pcm.js'

	//可选引入可视化插件
	import 'recorder-core/src/extensions/waveview.js'
	import 'recorder-core/src/extensions/wavesurfer.view.js'

	import 'recorder-core/src/extensions/frequency.histogram.view.js'
	import 'recorder-core/src/extensions/lib.fft.js'

	/** 引入RecordApp **/
	import RecordApp from 'recorder-core/src/app-support/app.js'
	//【必须引入】uni-app支持文件
	import '../../uni_modules/Recorder-UniCore/app-uni-support.js'

	export default {
		mounted() {
			//App的renderjs必须调用的函数，传入当前模块this
			RecordApp.UniRenderjsRegister(this);
		},
		methods: {
			//这里定义的方法，在逻辑层中可通过 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接调用
			//调用逻辑层的方法，请直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 调用，二进制数据需转成base64来传递
		}
	}
</script>
<!-- #endif -->




<style>
	.recwave {
		border: 1px solid #ccc;
		height: 100px;
		width: 300px;
	}

	.recwave canvas {
		height: 100px;
		width: 300px;
	}
</style>